#include "button.h"

#include <esp_log.h>

static const char* TAG = "Button";
#if CONFIG_SOC_ADC_SUPPORTED
Button::Button(const button_adc_config_t& adc_cfg) {
    button_config_t button_config = {
        .type = BUTTON_TYPE_ADC,
        .long_press_time = 1000,
        .short_press_time = 50,
        .adc_button_config = adc_cfg
    };
    button_handle_ = iot_button_create(&button_config);
    if (button_handle_ == NULL) {
        ESP_LOGE(TAG, "Failed to create button handle");
        return;
    }
}
#endif

Button::Button(gpio_num_t gpio_num, bool active_high) : gpio_num_(gpio_num) {
    if (gpio_num == GPIO_NUM_NC) {
        return;
    }
    button_config_t button_config = {
        .type = BUTTON_TYPE_GPIO,
        .long_press_time = 1000,
        .short_press_time = 50,
        .gpio_button_config = {
            .gpio_num = gpio_num,
            .active_level = static_cast<uint8_t>(active_high ? 1 : 0)
        }
    };
    button_handle_ = iot_button_create(&button_config);
    if (button_handle_ == NULL) {
        ESP_LOGE(TAG, "Failed to create button handle");
        return;
    }
}

Button::~Button() {
    if (button_handle_ != NULL) {
        iot_button_delete(button_handle_);
    }
}

/**
 * @brief 注册按钮按下事件的回调函数
 *
 * 当按钮被按下时，会触发注册的回调函数。如果按钮句柄无效则直接返回。
 *
 * @param callback 要注册的回调函数，类型为 std::function<void()>
 */
void Button::OnPressDown(std::function<void()> callback) {
  if (button_handle_ == nullptr) {
    return;
  }
  on_press_down_ = callback;
  iot_button_register_cb(
      button_handle_,
      BUTTON_PRESS_DOWN,
      [](void *handle, void *usr_data) {
        Button* button = static_cast<Button*>(usr_data);
        if (button->on_press_down_) {
          button->on_press_down_();
        }
      },
      this);
}

/**
 * @brief 设置按钮释放事件的回调函数
 *
 * 当按钮被释放时，将调用指定的回调函数。
 * 如果按钮句柄无效，则直接返回不设置回调。
 *
 * @param callback 要设置的回调函数，无参数无返回值
 */
void Button::OnPressUp(std::function<void()> callback) {
  if (button_handle_ == nullptr) {
    return;
  }
  on_press_up_ = callback;
  iot_button_register_cb(
      button_handle_,
      BUTTON_PRESS_UP,
      [](void *handle, void *usr_data) {
        Button* button = static_cast<Button*>(usr_data);
        if (button->on_press_up_) {
          button->on_press_up_();
        }
      },
      this);
}

/**
 * @brief 设置按钮长按事件的回调函数
 *
 * 当按钮被长按时，将触发注册的回调函数。如果按钮句柄无效则直接返回。
 *
 * @param callback 长按事件触发时要执行的回调函数
 */
void Button::OnLongPress(std::function<void()> callback) {
  if (button_handle_ == nullptr) {
    return;
  }
  on_long_press_ = callback;
  iot_button_register_cb(
      button_handle_,
      BUTTON_LONG_PRESS_START,
      [](void *handle, void *usr_data) {
        Button* button = static_cast<Button*>(usr_data);
        if (button->on_long_press_) {
          button->on_long_press_();
        }
      },
      this);
}

/**
 * @brief 设置按钮单击事件回调函数
 *
 * 注册一个回调函数，当按钮被单击时触发。如果按钮句柄无效则直接返回。
 *
 * @param callback 无参数无返回值的回调函数，在按钮单击时被调用
 */
void Button::OnClick(std::function<void()> callback) {
  if (button_handle_ == nullptr) {
    return;
  }
  on_click_ = callback;
  iot_button_register_cb(
      button_handle_,
      BUTTON_SINGLE_CLICK,
      [](void *handle, void *usr_data) {
        Button* button = static_cast<Button*>(usr_data);
        if (button->on_click_) {
          button->on_click_();
        }
      },
      this);
}

/**
 * 注册双击按钮的回调函数
 *
 * @param callback 当按钮被双击时执行的回调函数
 * @note 如果按钮句柄无效(button_handle_为nullptr)，则直接返回不注册回调
 */
void Button::OnDoubleClick(std::function<void()> callback) {
  if (button_handle_ == nullptr) {
    return;
  }
  on_double_click_ = callback;
  iot_button_register_cb(
      button_handle_,
      BUTTON_DOUBLE_CLICK,
      [](void *handle, void *usr_data) {
        Button* button = static_cast<Button*>(usr_data);
        if (button->on_double_click_) {
          button->on_double_click_();
        }
      },
      this);
}
